// Hereditary Algortithm.cpp : Defines the entry point for the console application.
//

#include "reproduction.h"

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>

using namespace std;

int main(int argc, char* argv[])
{
    start:
    system("clear");
    srand((unsigned)time(0));            // seed random number

    FILE *output;
    output = fopen("output.txt","w+");
    
    int numGen            = 0;
    int numRun            = 0;
    int adamTrait            = 0;
    int eveTrait            = 0;
    int maxChildren            = 0;
    
    printf("The Matrix Population and Traits Simulation Algorithm v0.3a\n(c) Justin Barrick and Nick Lombardo 2011\n\nEnter maximum number of generations: ");
    scanf("%d",&numGen);
    printf("Enter number of times to run the simulation: ");
    scanf("%d",&numRun);
    printf("Enter Adam's traits (1 - dominant, 2 - recessive, 4 - hybrid): ");
    scanf("%d",&adamTrait);
    printf("Enter Eve's traits (1 - dominant, 2 - recessive, 4 - hybrid): ");
    scanf("%d",&eveTrait);
    printf("Enter maximum children: ");
    scanf("%d",&maxChildren);

    if ((adamTrait != 1 && adamTrait != 2 && adamTrait != 4) || (eveTrait != 1 && eveTrait != 2 && eveTrait != 4))
    {
        printf("Error! Please enter a valid value.\r\n");
        exit(1);
    }

    fprintf(output, "The Matrix Population and Traits Simulation Algorithm v0.3a\n(c) Justin Barrick and Nick Lombardo 2011\n\n");
    fprintf(output, "Max generations: %d, number of runs: %d, Adam's traits: %d, Eve's traits: %d, max children: %d\n",numGen,numRun,adamTrait,eveTrait,maxChildren);
    
    start2:
    
    int popCount0            = 0;
    int popCount1            = 0;
    int popCount2            = 2;
    int genSize            = 0;
    int run                = 0;
    int *popCountPnt1        = &popCount1;
    int *popCountPnt2        = &popCount2;
    double numDisaster        = 0;
    double numDeaths        = 0;
    double numPopDestroyed        = 0;
    double domFazed            = 0;
    double recFazed            = 0;
    double deadGen            = 0;
    double *numDisasterPnt        = &numDisaster;
    double *numDeathsPnt        = &numDeaths;
    time_t rawtime;
    time_t initialTime;
    time_t finalTime;
    time_t startTime;
    time_t endTime;
    struct tm * timeinfo;

    time(&startTime);

    Demographics demoMain;
    demoMain.numBoth       = 0;
    demoMain.numRecessive  = 0;
    demoMain.numDominant   = 0;
    demoMain.numMales      = 0;
    demoMain.numFemales    = 0;

    vector<Man> nextGen;                // initialize vector of next generations

    for(int iterations=0;iterations<numRun;iterations++)
    {
        a:

        time(&initialTime);
        time(&rawtime);
        timeinfo = localtime(&rawtime);

        printf("\nIteration #%d\n\tIteration started: %s",iterations+1,asctime(timeinfo));
        printf("\n\t[*] Generation Count: 0\n\t[*] Total Population Count: 0\n\n\t");
        printf("\"And the Lord God formed man of the dust of the ground, \n\tand breathed into his nostrils the breath of life, \n\tand man became a living being.\"\n\t\t~ Genesis 2:7\n\n");
        printf("\t[*] Generation #1\n\t\t[*] Population Count: 2");
        fprintf(output, "\nIteration #%d\n\tIteration started: %s",iterations+1,asctime(timeinfo));
        fprintf(output, "\n\t[*] Generation Count: 0\n\t[*] Total Population Count: 0\n\n\t");
        fprintf(output, "\"And the Lord God formed man of the dust of the ground, \n\tand breathed into his nostrils the breath of life, \n\tand man became a living being.\"\n\t\t~ Genesis 2:7\n\n");
        fprintf(output, "\t[*] Generation #1\n\t\t[*] Population Count: 2");

        nextGen.push_back(Man());
        nextGen.push_back(Man());

        nextGen[0].maleFemale            = 0;            // make Adam
        nextGen[0].generationNumber      = 1;
        nextGen[0].dominantRecessiveBoth = adamTrait;
        nextGen[0].unmarriedMarried      = 0;
        popCount1++;
        demoMain = nextGen[0].refreshDemographics(demoMain,nextGen[0]);

        nextGen[1].maleFemale            = 1;            // make Eve
        nextGen[1].generationNumber      = 1;
        nextGen[1].dominantRecessiveBoth = eveTrait;
        nextGen[1].unmarriedMarried      = 0;
        popCount1++;
        demoMain = nextGen[1].refreshDemographics(demoMain,nextGen[1]);

        printf("\n\t\t[*] Number of Dominant: %d\n\t\t[*] Number of Recessive: %d\n\t\t[*] Number of Both: %d\n\t\t[*] Number of Males: %d\n\t\t[*] Number of Females: %d\n",demoMain.numDominant,demoMain.numRecessive,demoMain.numBoth,demoMain.numMales,demoMain.numFemales);
        fprintf(output, "\n\t\t[*] Number of Dominant: %d\n\t\t[*] Number of Recessive: %d\n\t\t[*] Number of Both: %d\n\t\t[*] Number of Males: %d\n\t\t[*] Number of Females: %d\n",demoMain.numDominant,demoMain.numRecessive,demoMain.numBoth,demoMain.numMales,demoMain.numFemales);

        popCount0 = popCount1;
        popCount1 = 0;

        demoMain.numDominant  = 0;
        demoMain.numRecessive = 0;
        demoMain.numBoth      = 0;
        demoMain.numMales     = 0;
        demoMain.numFemales   = 0;

        for(int h=1; h<=numGen; h++)
        {
            nextGen = nextGen[0].destroy(nextGen,output,numDisasterPnt,numDeathsPnt,&popCount0);
            genSize = nextGen.size();

            if(popCount0 < 2)
            {
                printf("\t\t[*] The population of the earth was destroyed.");    
                fprintf(output,"\t\t[*] The population of the earth was destroyed.");
                numPopDestroyed = numPopDestroyed + 1;
                break;
            }

            printf("\n\t[*] Generation #%d",h+1);
            fprintf(output, "\n\t[*] Generation #%d",h+1);

            for(int index=0;index<genSize;index++)
            {
                nextGen = nextGen[index].getMarried(nextGen,demoMain,index,h,maxChildren,popCountPnt1,popCountPnt2,genSize);
            }

            printf("\n\t\t[*] Generation Count: %d \n\t\t[*] Total Population Count: %d",popCount1,popCount2);
            fprintf(output, "\n\t\t[*] Generation Count: %d \n\t\t[*] Total Population Count: %d",popCount1,popCount2);

            if (demoMain.numFemales == 0 || demoMain.numMales == 0)
            {
                nextGen.clear();                // reset all values
                demoMain.numDominant  = 0;
                demoMain.numRecessive = 0;
                demoMain.numBoth      = 0;
                demoMain.numMales     = 0;
                demoMain.numFemales   = 0;
                popCount0              = 2;
                popCount1              = 0;
                popCount2             = 2; 
                deadGen                  = deadGen + 1;

                printf("\n\n\t\t[*] Dead Generation: Simulation Restarted\n");
                fprintf(output, "\n\n\t\t[*] Dead Generation: Simulation Restarted\n");

                break;
            }

            nextGen.erase(nextGen.begin(),nextGen.begin()+popCount0);
            random_shuffle(nextGen.begin(), nextGen.end());
            popCount0 = popCount1;
            popCount1 = 0;

            printf("\n\t\t[*] Number of Dominant: %d\n\t\t[*] Number of Recessive: %d\n\t\t[*] Number of Both: %d\n\t\t[*] Number of Males: %d\n\t\t[*] Number of Females: %d\n",demoMain.numDominant,demoMain.numRecessive,demoMain.numBoth,demoMain.numMales,demoMain.numFemales);
            fprintf(output, "\n\t\t[*] Number of Dominant: %d\n\t\t[*] Number of Recessive: %d\n\t\t[*] Number of Both: %d\n\t\t[*] Number of Males: %d\n\t\t[*] Number of Females: %d\n",demoMain.numDominant,demoMain.numRecessive,demoMain.numBoth,demoMain.numMales,demoMain.numFemales);    

            if(demoMain.numRecessive == 0 && demoMain.numBoth == 0)
            {
                recFazed = recFazed + 1;
                time(&rawtime);
                timeinfo = localtime(&rawtime);

                printf("\n\t\t[*] Recessive trait fazed out, simulation complete.\n");
                fprintf(output,"\n\t\t[*] Recessive trait fazed out, simulation complete.\n");
                break;
            }

            if(demoMain.numDominant == 0 && demoMain.numBoth == 0)
            {
                domFazed = domFazed + 1;
                time(&rawtime);
                timeinfo = localtime(&rawtime);

                printf("\n\t\t[*] Dominant trait fazed out, simulation complete.\n");
                fprintf(output,"\n\t\t[*] Dominant trait fazed out, simulation complete.\n");
                break;
            }

            demoMain.numDominant  = 0;
            demoMain.numRecessive = 0;
            demoMain.numBoth      = 0;
            demoMain.numMales     = 0;
            demoMain.numFemales   = 0;
        }

        nextGen.clear();                // reset all values
        demoMain.numDominant  = 0;
        demoMain.numRecessive = 0;
        demoMain.numBoth      = 0;
        demoMain.numMales     = 0;
        demoMain.numFemales   = 0;

        time(&rawtime);
        timeinfo = localtime(&rawtime);

        printf("\n\n\tIteration completed: %s \tIteration Run Time: %d seconds.\n",asctime(timeinfo),time(&finalTime)-initialTime);
        fprintf(output,"\n\n\tIteration completed: %s \tIteration Run Time: %d seconds.\n",asctime(timeinfo),time(&finalTime)-initialTime);
    }

    printf("\n------------------------------------------\n");
    printf("\n\tSimulation Results:\n\n\tSimulation Run Time: %d seconds\n\t",time(&endTime)-startTime);
    printf("Trait Statistics: \n\t\tPercent Dominant Fazed Out: %.2f%\n\t\tPercent Recessive Fazed Out: %.2f%\n\n\t",(domFazed/numRun)*100,(recFazed/numRun)*100);
    printf("Population Statistics: \n\t\tPopulations Died Out: %d\n\t\tDisasters That Occured: %d\n\t\tPeople That Died: %d\n\t\tPopulations Destroyed: %d\n\t\tPercent Populations Eliminated: %.2f%\n",(int)deadGen,(int)numDisaster,(int)numDeaths,(int)numPopDestroyed,((numPopDestroyed+deadGen)/numRun)*100);
    printf("\n\t\tPercent Successful: %.2f%\n",((numRun-(deadGen+numPopDestroyed))/numRun)*100);
    fprintf(output,"\n------------------------------------------\n");
    fprintf(output,"\n\tSimulation Results:\n\n\tSimulation Run Time: %d seconds\n\t",time(&endTime)-startTime);
    fprintf(output,"Trait Statistics: \n\t\tPercent Dominant Fazed Out: %.2f%\n\t\tPercent Recessive Fazed Out: %.2f%\n\n\t",(domFazed/numRun)*100,(recFazed/numRun)*100);
    fprintf(output,"Population Statistics: \n\t\tPopulations Died Out: %d\n\t\tDisasters That Occured: %d\n\t\tPeople That Died: %d\n\t\tPopulations Destroyed: %d\n\t\tPercent Populations Eliminated: %.2f%\n",(int)deadGen,(int)numDisaster,(int)numDeaths,(int)numPopDestroyed,((numPopDestroyed+deadGen)/numRun)*100);
    fprintf(output,"\n\t\tPercent Successful: %.2f%\n",((numRun-(deadGen+numPopDestroyed))/numRun)*100);
    
    printf("\nRun again? (1-yes, 2-no): ");
    scanf("%d",&run);
    if(run == 1)
    {
        printf("Run same sim again? (1-yes, 2-no): ");
        scanf("%d",&run);
        if(run == 1) goto start2;
        else goto start;
    }
    fclose(output);
    return 0;
}
